package edu.ptu.shortlink.project.service.impl;


import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import edu.ptu.shortlink.project.dao.entity.*;
import edu.ptu.shortlink.project.dao.mapper.*;
import edu.ptu.shortlink.project.dto.req.ShortLinkGroupStatsAccessRecordReqDTO;
import edu.ptu.shortlink.project.dto.req.ShortLinkGroupStatsReqDTO;
import edu.ptu.shortlink.project.dto.req.ShortLinkStatsAccessRecordReqDTO;
import edu.ptu.shortlink.project.dto.req.ShortLinkStatsReqDTO;
import edu.ptu.shortlink.project.dto.resp.*;
import edu.ptu.shortlink.project.service.IShortLinkStatsService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @BelongsProject: shortlink
 * @BelongsPackage: edu.ptu.shortlink.project.service.impl
 * @Author: HYJ
 * @CreateTime: 2025-05-08  19:45
 * @Description: TODO
 * @Version: 1.0
 */
@Service
@RequiredArgsConstructor
public class ShortLinkStatsServiceImpl implements IShortLinkStatsService {

    private final LinkAccessLogsMapper linkAccessLogsMapper;
    private final LinkAccessStatsMapper linkAccessStatsMapper;
    private final LinkLocaleStatsMapper linkLocaleStatsMapper;
    private final LinkBrowserStatsMapper linkBrowserStatsMapper;
    private final LinkOsStatsMapper linkOsStatsMapper;
    private final LinkDeviceStatsMapper linkDeviceStatsMapper;
    private final LinkNetworkStatsMapper linkNetworkStatsMapper;


    @Override
    public ShortLinkStatsRespDTO oneShortLinkStats(ShortLinkStatsReqDTO requestParam) {

        List<LinkAccessStatsDO> listStatsByShortLink = linkAccessStatsMapper.listStatsByShortLink(requestParam);

        // 空则返回->说明短链接没有被访问过
        if (CollUtil.isEmpty(listStatsByShortLink)) {
            return null;
        }

        //基础访问数据
        LinkAccessStatsDO pvUvUidStatsByShortLink = linkAccessLogsMapper.findPvUvUidStatsByShortLink(requestParam);

        //基础访问数据详细
        ArrayList<ShortLinkAccessStatsDailyRespDTO> daily = new ArrayList<>();

        //生成日期范围列表
        List<String> rangDates = DateUtil.rangeToList(
                DateUtil.parse(requestParam.getStartDate()),
                DateUtil.parse(requestParam.getEndDate()),
                DateField.DAY_OF_YEAR
        ).stream().map(DateUtil::formatDate).toList();

        //填充日期范围列表
        rangDates.forEach(date -> listStatsByShortLink.stream()
                .filter(item -> Objects.equals(date, DateUtil.formatDate(item.getDate())))
                .findFirst()
                .ifPresentOrElse(
                        item -> {
                            ShortLinkAccessStatsDailyRespDTO dailyReqDTO = ShortLinkAccessStatsDailyRespDTO.builder()
                                    .date(date)
                                    .uv(item.getUv())
                                    .pv(item.getPv())
                                    .uip(item.getUip())
                                    .build();
                            daily.add(dailyReqDTO);
                        },//有数据则构建DTO
                        () -> {
                            ShortLinkAccessStatsDailyRespDTO dailyReqDTO = ShortLinkAccessStatsDailyRespDTO.builder()
                                    .date(date)
                                    .uv(0)
                                    .pv(0)
                                    .uip(0)
                                    .build();
                            daily.add(dailyReqDTO);//无数据默认填充0
                        }));
        //地区访问数据(国内)
        ArrayList<ShortLinkStatsLocaleCNRespDTO> localeStats = new ArrayList<>();
        List<LinkLocaleStatsDO> listedLocaleByShortLink = linkLocaleStatsMapper.listLocaleByShortLink(requestParam);

        //获取cnt总和
        int localeSum = listedLocaleByShortLink.stream()
                .mapToInt(LinkLocaleStatsDO::getCnt)
                .sum();

        //填充地区访问数据(国内)
        listedLocaleByShortLink.forEach(locale -> {
            double percent = (double) locale.getCnt() / localeSum;
            double ratio = Math.round(percent * 100.0) / 100.0;
            ShortLinkStatsLocaleCNRespDTO localeCnRespDTO = ShortLinkStatsLocaleCNRespDTO.builder()
                    .ratio(ratio)
                    .cnt(locale.getCnt())
                    .locale(locale.getProvince())
                    .build();
            localeStats.add(localeCnRespDTO);
        });

        //小时访问
        ArrayList<Integer> hourStats = new ArrayList<>();
        List<LinkAccessStatsDO> listHourStatsByShortLink = linkAccessStatsMapper.listHourStatsByShortLink(requestParam);

        //填充小时访问数据
        for (int i = 0; i < 24; i++) {
            AtomicInteger hour = new AtomicInteger(i);
            Integer hourCnt = listHourStatsByShortLink.stream()
                    .filter(item -> Objects.equals(hour.get(), item.getHour()))
                    .findFirst()
                    .map(LinkAccessStatsDO::getPv)
                    .orElse(0);
            hourStats.add(hourCnt);
        }

        //高频ip详细
        ArrayList<ShortLinkStatsTopIpRespDTO> topIpStats = new ArrayList<>();
        List<HashMap<String, Object>> listTopIpByShortLink = linkAccessLogsMapper.listTopIpByShortLink(requestParam);

        //填充高频ip详细
        listTopIpByShortLink.forEach(item -> {
            ShortLinkStatsTopIpRespDTO topIpRespDTO = ShortLinkStatsTopIpRespDTO.builder()
                    .ip(item.get("ip").toString())
                    .cnt(Integer.parseInt(item.get("count").toString()))
                    .build();
            topIpStats.add(topIpRespDTO);
        });

        //一周访问量
        ArrayList<Integer> weekStats = new ArrayList<>();
        List<LinkAccessStatsDO> listWeekStatsByShortLink = linkAccessStatsMapper.listWeekStatsByShortLink(requestParam);

        //填充一周访问量
        for (int i = 1; i <= 7; i++) {
            AtomicInteger weedDay = new AtomicInteger(i);
            Integer weekCnt = listWeekStatsByShortLink.stream()
                    .filter(item -> Objects.equals(item.getWeekday(), weedDay.get()))
                    .findFirst()
                    .map(LinkAccessStatsDO::getPv)
                    .orElse(0);
            weekStats.add(weekCnt);
        }
        //浏览器访问量
        ArrayList<ShortLinkStatsBrowserRespDTO> browserStats = new ArrayList<>();
        List<HashMap<String, Object>> listBrowserStatsByShortLink = linkBrowserStatsMapper.listBrowserStatsByShortLink(requestParam);

        int browserSum = listBrowserStatsByShortLink.stream()
                .mapToInt(e -> Integer.parseInt(e.get("count").toString()))
                .sum();
        //填充浏览器访问量
        listBrowserStatsByShortLink.forEach(item -> {
            double percent = (double) Integer.parseInt(item.get("count").toString()) / browserSum;
            double ratio = Math.round(percent * 100.0) / 100.0;
            ShortLinkStatsBrowserRespDTO browserRespDTO = ShortLinkStatsBrowserRespDTO.builder()
                    .browser(item.get("browser").toString())
                    .ratio(ratio)
                    .cnt(Integer.parseInt(item.get("count").toString()))
                    .build();
            browserStats.add(browserRespDTO);
        });

        //操作系统
        ArrayList<ShortLinkStatsOsRespDTO> osStats = new ArrayList<>();
        List<HashMap<String, Object>> listOsStatsByShortLink = linkOsStatsMapper.listOsStatsByShortLink(requestParam);

        int osSum = listOsStatsByShortLink.stream()
                .mapToInt(e -> Integer.parseInt(e.get("count").toString()))
                .sum();
        listOsStatsByShortLink.forEach(item -> {
            double percent = (double) Integer.parseInt(item.get("count").toString()) / osSum;
            double ratio = Math.round(percent * 100.0) / 100.0;
            ShortLinkStatsOsRespDTO osRespDTO = ShortLinkStatsOsRespDTO.builder()
                    .os(item.get("os").toString())
                    .ratio(ratio)
                    .cnt(Integer.parseInt(item.get("count").toString()))
                    .build();
            osStats.add(osRespDTO);
        });

        //访客访问类型详细
        ArrayList<ShortLinkStatsUvRespDTO> uvTypeStats = new ArrayList<>();
        HashMap<String, Object> findUvTypeByShortLink = linkAccessLogsMapper.findUvTypeCntByShortLink(requestParam);
        //老访客数量
        int oldUserCnt = Integer.parseInt(
                Optional.ofNullable(findUvTypeByShortLink)
                        .map(e -> e.get("oldUserCnt"))
                        .map(Object::toString)
                        .orElse("0")
        );

        //新用户数量
        int newUserCnt = Integer.parseInt(
                Optional.ofNullable(findUvTypeByShortLink)
                        .map(e -> e.get("newUserCnt"))
                        .map(Object::toString)
                        .orElse("0")
        );

        int uvSum = oldUserCnt + newUserCnt;
        double oldUserRatio = Math.round((double) oldUserCnt / uvSum * 100.0) / 100.0;
        double newUserRatio = Math.round((double) newUserCnt / uvSum * 100.0) / 100.0;

        ShortLinkStatsUvRespDTO oldUvReqDTO = ShortLinkStatsUvRespDTO.builder()
                .uvType("oldUser")
                .cnt(oldUserCnt)
                .ratio(oldUserRatio)
                .build();
        uvTypeStats.add(oldUvReqDTO);

        ShortLinkStatsUvRespDTO newUvReqDTO = ShortLinkStatsUvRespDTO.builder()
                .uvType("newUser")
                .cnt(newUserCnt)
                .ratio(newUserRatio)
                .build();
        uvTypeStats.add(newUvReqDTO);

        //访问设备统计
        List<ShortLinkStatsDeviceRespDTO> deviceStats = new ArrayList<>();
        List<LinkDeviceStatsDO> listDeviceStatsByShortLink = linkDeviceStatsMapper.listDeviceStatsByShortLink(requestParam);

        int sum = listDeviceStatsByShortLink.stream()
                .mapToInt(LinkDeviceStatsDO::getCnt)
                .sum();
        listDeviceStatsByShortLink.forEach(item -> {
            double percent = (double) item.getCnt() / sum;
            double ratio = Math.round(percent * 100.0) / 100.0;
            ShortLinkStatsDeviceRespDTO deviceRespDTO = ShortLinkStatsDeviceRespDTO.builder()
                    .device(item.getDevice())
                    .cnt(item.getCnt())
                    .ratio(ratio)
                    .build();
            deviceStats.add(deviceRespDTO);
        });

        //网络类型统计
        List<ShortLinkStatsNetworkRespDTO> networkStats = new ArrayList<>();
        List<LinkNetworkStatsDO> listNetworkStatsByShortLink = linkNetworkStatsMapper.listNetworkStatsByShortLink(requestParam);

        int networkSum = listNetworkStatsByShortLink.stream()
                .mapToInt(LinkNetworkStatsDO::getCnt)
                .sum();
        listNetworkStatsByShortLink.forEach(item -> {
            double percent = (double) item.getCnt() / networkSum;
            double ratio = Math.round(percent * 100.0) / 100.0;
            ShortLinkStatsNetworkRespDTO networkRespDTO = ShortLinkStatsNetworkRespDTO.builder()
                    .network(item.getNetwork())
                    .cnt(item.getCnt())
                    .ratio(ratio)
                    .build();
            networkStats.add(networkRespDTO);
        });


        return ShortLinkStatsRespDTO.builder()
                .pv(pvUvUidStatsByShortLink.getPv())
                .uv(pvUvUidStatsByShortLink.getUv())
                .uip(pvUvUidStatsByShortLink.getUip())
                .daily(daily)
                .localeCnStats(localeStats)
                .hourStats(hourStats)
                .topIpStats(topIpStats)
                .weekdayStats(weekStats)
                .networkStats(networkStats)
                .browserStats(browserStats)
                .osStats(osStats)
                .uvTypeStats(uvTypeStats)
                .deviceStats(deviceStats)
                .build();

    }

    @Override
    public ShortLinkStatsRespDTO groupShortLinkStats(ShortLinkGroupStatsReqDTO requestParam) {
        List<LinkAccessStatsDO> listStatsByGroup = linkAccessStatsMapper.listStatsByGroup(requestParam);
        // 空则返回->说明短链接没有被访问过
        if (CollUtil.isEmpty(listStatsByGroup)) {
            return null;
        }
        //基础访问数据
        LinkAccessStatsDO pvUvUidStatsByGroup = linkAccessLogsMapper.findPvUvUidStatsByGroup(requestParam);
        //基础访问数据详细
        ArrayList<ShortLinkAccessStatsDailyRespDTO> daily = new ArrayList<>();

        //生成日期范围列表
        List<String> rangeDates = DateUtil.rangeToList(DateUtil.parse(requestParam.getStartDate()), DateUtil.parse(requestParam.getEndDate()), DateField.DAY_OF_YEAR).stream()
                .map(DateUtil::formatDate)
                .toList();

        //填充日期范围列表
        rangeDates.forEach(each -> listStatsByGroup.stream()
                .filter(item -> Objects.equals(each, DateUtil.formatDate(item.getDate())))
                .findFirst()
                .ifPresentOrElse(
                        item -> {
                            ShortLinkAccessStatsDailyRespDTO dailyReqDTO = ShortLinkAccessStatsDailyRespDTO.builder()
                                    .date(each)
                                    .uv(item.getUv())
                                    .pv(item.getPv())
                                    .uip(item.getUip())
                                    .build();
                            daily.add(dailyReqDTO);
                        },
                        () -> {
                            ShortLinkAccessStatsDailyRespDTO dailyReqDTO = ShortLinkAccessStatsDailyRespDTO.builder()
                                    .pv(0)
                                    .uv(0)
                                    .uip(0)
                                    .date(each)
                                    .build();
                            daily.add(dailyReqDTO);
                        }));

        //地区访问数据(国内)
        ArrayList<ShortLinkStatsLocaleCNRespDTO> localeStats = new ArrayList<>();
        List<LinkLocaleStatsDO> listedLocaleByGroup = linkLocaleStatsMapper.listLocaleByGroup(requestParam);

        //获取cnt总和
        int localeSum = listedLocaleByGroup.stream()
                .mapToInt(LinkLocaleStatsDO::getCnt)
                .sum();
        //填充地区访问数据(国内)
        listedLocaleByGroup.forEach(locale -> {
            double percent = (double) locale.getCnt() / localeSum;
            double ratio = Math.round(percent * 100.0) / 100.0;
            ShortLinkStatsLocaleCNRespDTO localeCnRespDTO = ShortLinkStatsLocaleCNRespDTO.builder()
                    .ratio(ratio)
                    .cnt(locale.getCnt())
                    .locale(locale.getProvince())
                    .build();
            localeStats.add(localeCnRespDTO);
        });

        //小时访问
        ArrayList<Integer> hourStats = new ArrayList<>();
        List<LinkAccessStatsDO> listHourStatsByGroup = linkAccessStatsMapper.listHourStatsByGroup(requestParam);

        //填充小时访问数据
        for (int i = 0; i < 24; i++) {
            AtomicInteger hour = new AtomicInteger(i);
            Integer hourCnt = listHourStatsByGroup.stream()
                    .filter(item -> Objects.equals(hour.get(), item.getHour()))
                    .findFirst()
                    .map(LinkAccessStatsDO::getPv)
                    .orElse(0);
            hourStats.add(hourCnt);
        }
        //高频ip详细
        ArrayList<ShortLinkStatsTopIpRespDTO> topIpStats = new ArrayList<>();
        List<HashMap<String, Object>> listTopIpByGroup = linkAccessLogsMapper.listTopIpByGroup(requestParam);

        //填充高频ip详细
        listTopIpByGroup.forEach(item -> {
            ShortLinkStatsTopIpRespDTO topIpRespDTO = ShortLinkStatsTopIpRespDTO.builder()
                    .ip(item.get("ip").toString())
                    .cnt(Integer.parseInt(item.get("count").toString()))
                    .build();
            topIpStats.add(topIpRespDTO);
        });

        //一周访问量
        ArrayList<Integer> weekStats = new ArrayList<>();
        List<LinkAccessStatsDO> listWeekStatsByGroup = linkAccessStatsMapper.listWeekStatsByGroup(requestParam);

        //填充一周访问量
        for (int i = 1; i <= 7; i++) {
            AtomicInteger weedDay = new AtomicInteger(i);
            Integer weekCnt = listWeekStatsByGroup.stream()
                    .filter(item -> Objects.equals(item.getWeekday(), weedDay.get()))
                    .findFirst()
                    .map(LinkAccessStatsDO::getPv)
                    .orElse(0);
            weekStats.add(weekCnt);
        }

        //浏览器访问量
        ArrayList<ShortLinkStatsBrowserRespDTO> browserStats = new ArrayList<>();
        List<HashMap<String, Object>> listBrowserStatsByGroup = linkBrowserStatsMapper.listBrowserStatsByGroup(requestParam);

        //获取cnt总和
        int broswerSum = listBrowserStatsByGroup.stream()
                .mapToInt(e -> Integer.parseInt(e.get("count").toString()))
                .sum();
        listBrowserStatsByGroup.forEach(each -> {
            double percent = (double) Integer.parseInt(each.get("count").toString()) / broswerSum;
            double ratio = Math.round(percent * 100.0) / 100.0;
            ShortLinkStatsBrowserRespDTO browserRespDTO = ShortLinkStatsBrowserRespDTO.builder()
                    .browser(each.get("browser").toString())
                    .ratio(ratio)
                    .cnt(Integer.parseInt(each.get("count").toString()))
                    .build();
            browserStats.add(browserRespDTO);
        });

        //操作系统
        ArrayList<ShortLinkStatsOsRespDTO> osStats = new ArrayList<>();
        List<HashMap<String, Object>> listOsStatsByGroup = linkOsStatsMapper.listOsStatsByGroup(requestParam);

        int osSum = listOsStatsByGroup.stream()
                .mapToInt(e -> Integer.parseInt(e.get("count").toString()))
                .sum();

        listOsStatsByGroup.forEach(each -> {
            double percent = (double) Integer.parseInt(each.get("count").toString()) / osSum;
            double ratio = Math.round(percent * 100.0) / 100.0;
            ShortLinkStatsOsRespDTO osRespDTO = ShortLinkStatsOsRespDTO.builder()
                    .os(each.get("os").toString())
                    .ratio(ratio)
                    .cnt(Integer.parseInt(each.get("count").toString()))
                    .build();
            osStats.add(osRespDTO);
        });
        //访客访问类型详细
        ArrayList<ShortLinkStatsUvRespDTO> uvTypeStats = new ArrayList<>();
        HashMap<String, Object> findUvTypeByGroup = linkAccessLogsMapper.findUvTypeCntByGroup(requestParam);
        //老访客数量
        int oldUserCnt = Integer.parseInt(
                Optional.ofNullable(findUvTypeByGroup)
                        .map(e -> e.get("oldUserCnt"))
                        .map(Object::toString)
                        .orElse("0")
        );

        //新用户数量
        int newUserCnt = Integer.parseInt(
                Optional.ofNullable(findUvTypeByGroup)
                        .map(e -> e.get("newUserCnt"))
                        .map(Object::toString)
                        .orElse("0")
        );
        int uvSum = oldUserCnt + newUserCnt;
        double oldUserRatio = Math.round((double) oldUserCnt / uvSum * 100.0) / 100.0;
        double newUserRatio = Math.round((double) newUserCnt / uvSum * 100.0) / 100.0;

        ShortLinkStatsUvRespDTO oldUvReqDTO = ShortLinkStatsUvRespDTO.builder()
                .uvType("oldUser")
                .cnt(oldUserCnt)
                .ratio(oldUserRatio)
                .build();
        uvTypeStats.add(oldUvReqDTO);

        ShortLinkStatsUvRespDTO newUvReqDTO = ShortLinkStatsUvRespDTO.builder()
                .uvType("newUser")
                .cnt(newUserCnt)
                .ratio(newUserRatio)
                .build();
        uvTypeStats.add(newUvReqDTO);

        //访问设备统计
        List<ShortLinkStatsDeviceRespDTO> deviceStats = new ArrayList<>();
        List<LinkDeviceStatsDO> listDeviceStatsByGroup = linkDeviceStatsMapper.listDeviceStatsByGroup(requestParam);

        int deviceSum = listDeviceStatsByGroup.stream()
                .mapToInt(LinkDeviceStatsDO::getCnt)
                .sum();

        listDeviceStatsByGroup.forEach(item -> {
            double percent = (double) item.getCnt() / deviceSum;
            double ratio = Math.round(percent * 100.0) / 100.0;
            ShortLinkStatsDeviceRespDTO deviceRespDTO = ShortLinkStatsDeviceRespDTO.builder()
                    .device(item.getDevice())
                    .cnt(item.getCnt())
                    .ratio(ratio)
                    .build();
            deviceStats.add(deviceRespDTO);
        });

        //网络类型统计
        List<ShortLinkStatsNetworkRespDTO> networkStats = new ArrayList<>();
        List<LinkNetworkStatsDO> listNetworkStatsByGroup = linkNetworkStatsMapper.listNetworkStatsByGroup(requestParam);

        int networkSum = listNetworkStatsByGroup.stream()
                .mapToInt(LinkNetworkStatsDO::getCnt)
                .sum();

        listNetworkStatsByGroup.forEach(item -> {
            double percent = (double) item.getCnt() / networkSum;
            double ratio = Math.round(percent * 100.0) / 100.0;
            ShortLinkStatsNetworkRespDTO networkRespDTO = ShortLinkStatsNetworkRespDTO.builder()
                    .network(item.getNetwork())
                    .cnt(item.getCnt())
                    .ratio(ratio)
                    .build();
            networkStats.add(networkRespDTO);
        });

        return ShortLinkStatsRespDTO.builder()
                .pv(pvUvUidStatsByGroup.getPv())
                .uv(pvUvUidStatsByGroup.getUv())
                .uip(pvUvUidStatsByGroup.getUip())
                .daily(daily)
                .localeCnStats(localeStats)
                .hourStats(hourStats)
                .topIpStats(topIpStats)
                .weekdayStats(weekStats)
                .networkStats(networkStats)
                .browserStats(browserStats)
                .osStats(osStats)
                .uvTypeStats(uvTypeStats)
                .deviceStats(deviceStats)
                .build();


    }

    @Override
    public IPage<ShortLinkStatsAccessRecordRespDTO> shortLinkStatsAccessRecord(ShortLinkStatsAccessRecordReqDTO requestParam) {

        //查询出DO记录
        LambdaQueryWrapper<LinkAccessLogsDO> queryWrapper = Wrappers.lambdaQuery(LinkAccessLogsDO.class)
                .eq(LinkAccessLogsDO::getFullShortUrl, requestParam.getFullShortUrl())
                .between(LinkAccessLogsDO::getCreateTime, requestParam.getStartDate(), requestParam.getEndDate())
                .orderByDesc(LinkAccessLogsDO::getCreateTime);

        IPage<LinkAccessLogsDO> linkAccessLogsDOIPage = linkAccessLogsMapper.selectPage(requestParam, queryWrapper);

        //如果没有数据则返回空的分页数据
        if (CollUtil.isEmpty(linkAccessLogsDOIPage.getRecords())) {
            return new Page<>();
        }
        //获取到user列表
        List<String> userAccessLogsList = linkAccessLogsDOIPage.getRecords().stream()
                .map(LinkAccessLogsDO::getUser).toList();

        //将DO数据转为DTO数据
        IPage<ShortLinkStatsAccessRecordRespDTO> result = linkAccessLogsDOIPage.convert(item -> BeanUtil.toBean(item, ShortLinkStatsAccessRecordRespDTO.class));
        List<Map<String, Object>> uvTypeList = linkAccessLogsMapper.selectUvTypeByUser(
                requestParam.getGid(),
                requestParam.getFullShortUrl(),
                requestParam.getEnableStatus(),
                requestParam.getStartDate(),
                requestParam.getEndDate(),
                userAccessLogsList
        );

        //填充访问类型
        result.getRecords().forEach(each -> {
            String uvType = uvTypeList.stream()
                    .filter(item -> Objects.equals(each.getUser(), item.get("user")))//匹配同一个user
                    .findFirst()
                    .map(item -> item.get("uvType"))
                    .map(Object::toString)
                    .orElse("旧访客");
            each.setUvType(uvType);
        });
        return result;
    }

    @Override
    public IPage<ShortLinkStatsAccessRecordRespDTO> groupShortLinkStatsAccessRecord(ShortLinkGroupStatsAccessRecordReqDTO requestParam) {

        //查询出DO记录
        LambdaQueryWrapper<LinkAccessLogsDO> queryWrapper = Wrappers.lambdaQuery(LinkAccessLogsDO.class)
                .between(LinkAccessLogsDO::getCreateTime, requestParam.getStartDate(), requestParam.getEndDate())
                .orderByDesc(LinkAccessLogsDO::getCreateTime);

        IPage<LinkAccessLogsDO> linkAccessLogsDOIPage = linkAccessLogsMapper.selectPage(requestParam, queryWrapper);
        //如果没有数据则返回空的分页数据
        if (CollUtil.isEmpty(linkAccessLogsDOIPage.getRecords())) {
            return new Page<>();
        }

        //获取到user列表
        List<String> userAccessLogsList = linkAccessLogsDOIPage.getRecords().stream()
                .map(LinkAccessLogsDO::getUser).toList();

        IPage<ShortLinkStatsAccessRecordRespDTO> result = linkAccessLogsDOIPage.convert(each -> BeanUtil.toBean(each, ShortLinkStatsAccessRecordRespDTO.class));
        List<Map<String, Object>> uvTypeList = linkAccessLogsMapper.selectGroupUvTypeByUser(
                requestParam.getGid(),
                requestParam.getStartDate(),
                requestParam.getEndDate(),
                userAccessLogsList
        );

        result.getRecords().forEach(each -> {
            String uvType = uvTypeList.stream()
                    .filter(item -> Objects.equals(each.getUser(), item.get("user")))//匹配同一个user
                    .findFirst()
                    .map(item -> item.get("uvType"))
                    .map(Object::toString)
                    .orElse("旧访客");
        });
        return result;
    }
}

